package com.gxa.k12.common.util;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Random;

/**
 * @Author：Win
 * @Date: 2021/7/16 17:19
 * @Description: 普通工具方法
 */
public class GenericUtils {
    //    指定token的过期时间
    private static final long EXPIRE = 1000 * 60 * 60 * 24;
    //    根据指定密钥生成token
    private static final String APP_SECRET = "k12-online-education";

    private GenericUtils() {}

    /**
     * 生成token字符串的方法
     *
     * @param id       用户信息
     * @param nickname 用户信息
     * @return 生成的token字符串
     */
    public static String getJwtToken(String id, String nickname) {
        return Jwts.builder()
                //设置token的头部信息(使用的加密方式)
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //设置token的过期时间
                .setSubject(nickname)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //设置token的主体信息(包含的用户信息)
                .claim("id", id)
                .claim("nickname", nickname)
                //设置token的签名哈希(防伪标志)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
    }

    /**
     * 判断token是否存在与有效
     *
     * @param jwtToken token字符串
     * @return true or false
     */
    private static boolean checkToken(String jwtToken) {
//        从request对象中获取token,如果token不存在则返回false
        if (StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断request中的token是否存在与有效
     *
     * @param request 请求对象
     * @return true or false
     */
    public static boolean checkToken(HttpServletRequest request) {
//        从request对象中获取token
        String jwtToken = request.getHeader("token");
        return checkToken(jwtToken);
    }

    /**
     * 根据token获取用户信息
     *
     * @param request 请求对象
     * @return 用户信息
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
//        从request对象中获取token
        String jwtToken = request.getHeader("token");
//        如果token对象不存在,则返回""字符串
        if (StringUtils.isEmpty(jwtToken)) return "";
//        反解析token信息
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
//        获取token主体信息
        Claims claims = claimsJws.getBody();
//        获取需要的用户信息
        return (String) claims.get("id");
    }


    /**
     * 获取异常信息,并将其写入日志文件中
     *
     * @param t 具体异常
     * @return 异常信息
     */
    public static String getExceptionMessage(Throwable t) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 将出错的栈信息输出到printWriter中
            t.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }

    private static final DecimalFormat FOUR = new DecimalFormat("0000");
    private static final DecimalFormat SIX = new DecimalFormat("000000");
    private static final Random RANDOM = new Random();

    /**
     * 获取4位伪随机数
     *
     * @return 随机数
     */
    public static String getFourBitRandom() {
        return FOUR.format(RANDOM.nextInt(10000));
    }

    /**
     * 获取6位伪随机数
     *
     * @return 随机数
     */
    public static String getSixBitRandom() {

        return SIX.format(RANDOM.nextInt(1000000));
    }

    /**
     * MD5加密
     *
     * @param strSrc 目标字符串
     * @return 加密后的字符串
     */
    public static String encrypt(String strSrc) {
        try {
            char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
            byte[] bytes = strSrc.getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (byte b : bytes) {
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错！！+" + e);
        }
    }
}
